#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define rr register
using namespace std;

const int maxn=1e5+10;
const int inf=0x3f3f3f3f;
int n,m,s,t,ans;
int vis[maxn];
struct edge{
    int to,c,rev;//边里存储的分别是连接点、容量、反向边的编号
    edge(int x,int y,int z):to(x),c(y),rev(z){}
};
vector<edge>a[maxn];

inline void add(int x,int y,int z){
    int S1=a[y].size(),S2=a[x].size();
    a[x].push_back(edge(y,z,S1));
    //对于一条边，它的反向边的编号就是它所连向的点此时所拥有的边的个数+1
    //但vector里数组下标都是0开始的，所以直接是a[x].size()就好了
    a[y].push_back(edge(x,0,S2));
}

inline int dfs(int x,int y,int now){
    if(x==y)return now;
    vis[x]=1;
    int S=a[x].size();
    for(rr int i=0;i<S;++i){
        int v=a[x][i].to,f=a[x][i].c,re=a[x][i].rev;
        if(!vis[v] && f>0){
            int tmp=dfs(v,y,min(f,now));//从子节点开始找增广路
            if(tmp>0){//如果存在增广路
                a[x][i].c-=tmp;//容量减去增加的流量就相当于流量加上这么多
                a[v][re].c+=tmp;//正向边流量增加相当于反向边流量减少
                return tmp;
            }
        }
    }
    return 0;
}

inline int max_flow(int x,int y){
    int flow=0,f=0;
    do{
        flow+=f;
        memset(vis,0,sizeof(vis));
        f=dfs(x,y,inf);
        //寻找增广路，因为在寻找过程中要取此时的流量与该路径的容量的min值，故流量初始化为极大值
    }while(f!=0);//当存在增广路的时候就继续找
    return flow;
}

int main(){
    cin>>n>>m>>s>>t;
    memset(a,0,sizeof(a));
    for(rr int i=1;i<=m;++i){
        int x,y,z;cin>>x>>y>>z;
        add(x,y,z);
    }
    ans=max_flow(s,t);
    printf("%d\n",ans);
    return 0;
}